package com.easylinkin.linkappapi.elasticsearch.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.alarm.entity.AlarmNoticeTemplet;
import com.easylinkin.linkappapi.alarm.mapper.AlarmNoticeTempletMapper;
import com.easylinkin.linkappapi.analyze.entity.AnalyzeDateSource;
import com.easylinkin.linkappapi.analyze.service.AnalyzeDateSourceService;
import com.easylinkin.linkappapi.common.utils.DateUtil;
import com.easylinkin.linkappapi.common.utils.message.SendEmailUtil;
import com.easylinkin.linkappapi.common.utils.message.SendMessageUtil;
import com.easylinkin.linkappapi.elasticsearch.entity.BankAlarmNotice;
import com.easylinkin.linkappapi.elasticsearch.entity.BankEnergyAlarmRule;
import com.easylinkin.linkappapi.elasticsearch.entity.EsQuerymodel;
import com.easylinkin.linkappapi.elasticsearch.entity.MomStatisticModel;
import com.easylinkin.linkappapi.elasticsearch.mapper.BankAlarmNoticeMapper;
import com.easylinkin.linkappapi.elasticsearch.mapper.BankAlarmRuleMapper;
import com.easylinkin.linkappapi.elasticsearch.service.IBankAlarmRuleService;
import com.easylinkin.linkappapi.elasticsearch.service.IEService;
import com.easylinkin.linkappapi.elasticsearch.util.EsCalendar;
import com.easylinkin.linkappapi.taskscheduler.constant.JobEntityConstant.IsNowRunEnum;
import com.easylinkin.linkappapi.taskscheduler.constant.JobEntityConstant.JobTaskTypeEnum;
import com.easylinkin.linkappapi.taskscheduler.constant.JobEntityConstant.JobTypeEnum;
import com.easylinkin.linkappapi.taskscheduler.entity.JobEntity;
import com.easylinkin.linkappapi.taskscheduler.service.JobEntityService;
import com.easylinkin.linkappapi.taskscheduler.service.TaskSchedulerService;
import com.easylinkin.linkappapi.tenant.entity.LinkappTenant;
import com.easylinkin.linkappapi.tenant.sevice.LinkappTenantService;
import com.fasterxml.jackson.core.JsonProcessingException;
import java.io.Serializable;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

/**
 * es数据分析主要流程是：1 构建业务 2 根据业务构建条件  3 对查询结果进行解析处理
 *
 * @author lhy
 */
@Service
public class BankAlarmRuleServiceImpl extends ServiceImpl<BankAlarmRuleMapper, BankEnergyAlarmRule> implements IBankAlarmRuleService, Job, Serializable {


    private static final Logger LOGGER = LoggerFactory.getLogger(BankAlarmRuleServiceImpl.class);
    @Lazy
    @Autowired
    private SendEmailUtil sendEmailUtil;
    @Lazy
    @Autowired
    private SendMessageUtil sendMessageUtil;
    @Autowired
    AnalyzeDateSourceService analyzeDateSourceService;
    /**
     *
     */
    private static final long serialVersionUID = 1L;
    private static final String PREFIX = "bankAlarm";
    private static final Integer WEEKTYPE = 1;
    private static final Integer MONTHTYPE = 2;
    private static final String CLOSE = "0";
    private static final String OPEN = "1";
    private static final String PHONEFIELD = "phone";
    private static final String EMAILFIELD = "email";
    private static final String THRFIELD = "alarmThr";
    private static final String DATASOURCEIDFIELD = "dataSourceId";
    private static final String ISNOTICEFIELD = "isNotice";
    private static final String ENERGYKINDFIELD = "energyKind";
    private static final String ALARMTYPEFIELD = "alarmType";


    private static final String PHONETEMPLETID = "14";
    private static final String EMAILTEMPLETID = "15";

    private static final String CURRENT = "current";
    private static final String MOM = "mom";
    private static final String SUMENERGY = "sumEnergy";
    @Autowired
    TaskSchedulerService taskSchedulerService;
    @Autowired
    LinkappTenantService linkappTenantService;
    @Autowired
    private JobEntityService jobEntityService;
    @Autowired
    private BankAlarmNoticeMapper bankAlarmNoticeMapper;
    @Autowired
    IEService esRealServiceImpl;
    @Autowired
    AlarmNoticeTempletMapper alarmNoticeTempletMapper;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean createRule(BankEnergyAlarmRule bankEnergyAlarmRule) {
        Assert.notNull(bankEnergyAlarmRule, "参数为空");
        validParam(bankEnergyAlarmRule);
        JobEntity jobEntity = new JobEntity();
        initial(bankEnergyAlarmRule, jobEntity);
        taskSchedulerService.saveTask(jobEntity);
        bankEnergyAlarmRule.setJobId(jobEntity.getId());
        save(bankEnergyAlarmRule);
        return true;
    }


    private void validParam(BankEnergyAlarmRule bankEnergyAlarmRule) {
        String dataSourceId = bankEnergyAlarmRule.getDataSourceId();
        Integer alarmType = bankEnergyAlarmRule.getAlarmType();
        String status = bankEnergyAlarmRule.getStatus();
        Integer isNotice = bankEnergyAlarmRule.getIsNotice();
        String cronExpression = bankEnergyAlarmRule.getCronExpression();
        Float alarmThr = bankEnergyAlarmRule.getAlarmThr();
        Assert.isTrue(StringUtils.isNotBlank(dataSourceId), "数据源Id为空");
        Assert.isTrue(!ObjectUtils.isEmpty(alarmType), "确认按周还是月进行告警");
        Assert.isTrue(WEEKTYPE.equals(alarmType) || MONTHTYPE.equals(alarmType), "只能按周还是月进行告警");
        Assert.isTrue(StringUtils.isNotBlank(status), "确认禁用还是启用");
        Assert.isTrue(CLOSE.equals(status) || OPEN.equals(status), "只能选择禁用还是启用");
        Assert.isTrue(isNotice != null, "确认禁用还是启用");
        Assert.isTrue(isNotice == 0 || isNotice == 1, "只能选择禁用还是启用");
        Assert.isTrue(StringUtils.isNotBlank(cronExpression), "cron 表达式为空");
        Assert.isTrue(alarmThr != null, "告警阀值为空");
        Assert.isTrue(alarmThr > 0, "告警阀值不符合要求");

    }


    /**
     * 更新告警规则
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateRule(BankEnergyAlarmRule bankEnergyAlarmRule) {
        Assert.notNull(bankEnergyAlarmRule, "参数不能为空");
        Assert.hasLength(bankEnergyAlarmRule.getId(), "告警规则id为空");
        validParam(bankEnergyAlarmRule);
        JobEntity newJobEntity = new JobEntity();
        BankEnergyAlarmRule oldRule = this.getById(bankEnergyAlarmRule.getId());
        bankEnergyAlarmRule.setJobId(oldRule.getJobId());
        initial(bankEnergyAlarmRule, newJobEntity);
        Assert.notNull(oldRule, "告警规则不存在");
        bankEnergyAlarmRule.setAlarmType(oldRule.getAlarmType());
        bankEnergyAlarmRule.setDataSourceId(oldRule.getDataSourceId());
        bankEnergyAlarmRule.setEnergyKind(oldRule.getEnergyKind());
        bankEnergyAlarmRule.setStatus(oldRule.getStatus());

        if (StringUtils.isNotEmpty(newJobEntity.getId())) {

            JobEntity oldJob = jobEntityService.getById(newJobEntity.getId());

            oldJob.setCronExpression(newJobEntity.getCronExpression());

            oldJob.setParams(newJobEntity.getParams());

            taskSchedulerService.updateTask(oldJob);
        }
        updateById(bankEnergyAlarmRule);
        return true;
    }

    /**
     * 暂停告警规则
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean pauseRule(BankEnergyAlarmRule bankEnergyAlarmRule) {
        Assert.notNull(bankEnergyAlarmRule, "参数不能为空");
        Assert.hasLength(bankEnergyAlarmRule.getId(), "参数id为空");
        BankEnergyAlarmRule oldRule = this.getById(bankEnergyAlarmRule.getId());
        Assert.notNull(oldRule, "规则不存在！");
        JobEntity oldJob = jobEntityService.getById(oldRule.getJobId());
        oldRule.setStatus(CLOSE);
        this.updateById(oldRule);
        taskSchedulerService.pause(oldJob);
        LOGGER.info("暂停贷后告警规则：" , oldJob);
        return true;
    }

    /**
     * 重启告警规则
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean resumeRule(BankEnergyAlarmRule bankEnergyAlarmRule) {
        Assert.notNull(bankEnergyAlarmRule, "参数不能为空");
        Assert.hasLength(bankEnergyAlarmRule.getId(), "参数id为空");
        BankEnergyAlarmRule oldRule = this.getById(bankEnergyAlarmRule.getId());
        Assert.notNull(oldRule, "规则不存在！");
        JobEntity oldJob = jobEntityService.getById(oldRule.getJobId());
        oldRule.setStatus(OPEN);
        this.updateById(oldRule);
        taskSchedulerService.resume(oldJob);
        return true;
    }

    /**
     * 删除告警规则 数据源删除的时候调用
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeRule(BankEnergyAlarmRule bankEnergyAlarmRule) {
        Assert.notNull(bankEnergyAlarmRule, "参数不能为空");
        Assert.hasLength(bankEnergyAlarmRule.getId(), "参数id为空");
        this.removeRule(bankEnergyAlarmRule);
        JobEntity oldJob = jobEntityService.getById(bankEnergyAlarmRule.getJobId());
        taskSchedulerService.remove(oldJob);
        return true;
    }


    public void initial(BankEnergyAlarmRule bankEnergyAlarmRule, JobEntity jobEntity) {
        Integer alarmType = bankEnergyAlarmRule.getAlarmType();
        JSONObject parmObject = new JSONObject();
        parmObject.put(PHONEFIELD, bankEnergyAlarmRule.getPhone());
        parmObject.put(EMAILFIELD, bankEnergyAlarmRule.getMail());
        parmObject.put(THRFIELD, bankEnergyAlarmRule.getAlarmThr());
        parmObject.put(DATASOURCEIDFIELD, bankEnergyAlarmRule.getDataSourceId());
        parmObject.put(ISNOTICEFIELD, bankEnergyAlarmRule.getIsNotice());
        parmObject.put(ENERGYKINDFIELD, bankEnergyAlarmRule.getEnergyKind());
        if (!ObjectUtils.isEmpty(alarmType)) {
            parmObject.put(ALARMTYPEFIELD, bankEnergyAlarmRule.getAlarmType());
        }
        String parmString = parmObject.toString();
        String jobId = bankEnergyAlarmRule.getJobId();
        if (StringUtils.isNotEmpty(jobId)) {
            jobEntity.setId(jobId);
        }
        String jobGroup = PREFIX + getTeantId();
        //    尽量使得任务名称唯一 以防根据名称执行 会执行到多个任务
        String jobName = bankEnergyAlarmRule.getDataSourceId() + bankEnergyAlarmRule.getEnergyKind() + bankEnergyAlarmRule.getAlarmType();
        jobEntity.setJobGroup(jobGroup);
        jobEntity.setJobName(jobName);
        jobEntity.setCronExpression(bankEnergyAlarmRule.getCronExpression());
        jobEntity.setJobStatus(bankEnergyAlarmRule.getStatus());
        Date date = new Date();
        jobEntity.setCreateTime(date);
        jobEntity.setModifyTime(date);
        jobEntity.setJobClassName(this.getClass().getName());
        setJobEntityDefaultProperty(jobEntity);
        jobEntity.setParams(parmString);
    }

    /**
     * 如果某些属性为空 给设置默认值
     */
    private void setJobEntityDefaultProperty(JobEntity jobEntity) {

        if (StringUtils.isEmpty(jobEntity.getJobTaskType())) {
            jobEntity.setJobTaskType(JobTaskTypeEnum.API.getType());
        }
        if (StringUtils.isEmpty(jobEntity.getJobType())) {
            jobEntity.setJobType(JobTypeEnum.CYCLE.getType());
        }
        if (StringUtils.isEmpty(jobEntity.getIsNowRun())) {
            jobEntity.setIsNowRun(IsNowRunEnum.YES.getType());
        }
    }


    private String getTeantId() {
        LinkappTenant currentTenant = linkappTenantService.currentTenant();
        Assert.notNull(currentTenant, "当前租户为空");
        Assert.notNull(currentTenant.getProjectId(), "当前租户项目id为空");
        String teantId = currentTenant.getId();
        return teantId;
    }


    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        String jobName = jobDetail.getKey().getName();
        String jobGroup = jobDetail.getKey().getGroup();
        LOGGER.info("intelligent-定时任务，任务分组：{}，任务名称：{}，任务触发时间：{}",
            jobGroup, jobName, DateUtil.getYYYYMMDDHHMMSSDate(new Date()));

        BankAlarmNotice bankAlarmNotice = new BankAlarmNotice();
        String parmString = jobDetail.getJobDataMap().getString("params");
	/* BankAlarmNotice  bankAlarmNotice =new BankAlarmNotice();
	 String  parmString ="{'dataSourceId':'bf5c851190960c2f8b14222b68c77873','energyKind':'electric','alarmType':1,'phone':'13037133906','isNotice':1,"
	 		+ "'email':'gqxuj@easylinkincom','alarmThr':2}";*/
        try {
            EsQuerymodel queryModel = new EsQuerymodel();
            bankAlarmNotice.initialBankAlarmNoticeFrmParmJson(parmString);
            if (bankAlarmNotice.getIsNotice() != null && bankAlarmNotice.getIsNotice() == 0) {
                return;
            }
            queryModel.setDataSourceId(bankAlarmNotice.getDataSourceId());
            queryModel.setUseKinds(bankAlarmNotice.getEnergyKind());
            queryModel.setCurrentEndTime(bankAlarmNotice.getCurrentEndTime());
            queryModel.setCurrentBeginTime(bankAlarmNotice.getCurrentBeginTime());
            queryModel.setMomStatisticKind(bankAlarmNotice.getAlarmType());
            MomStatisticModel momStatisticModel = esRealServiceImpl.getMomStatisticData(queryModel);
            LOGGER.info("贷后管理告警JOB执行查询环比数据结果为：" + momStatisticModel.toString());
            if (momStatisticModel != null && momStatisticModel.getStaticResultMap() != null) {
                Map<String, Map<String, Double>> staticResultMap = momStatisticModel.getStaticResultMap();
                Map<String, Double> sumerergyMap = staticResultMap.get(SUMENERGY);

                if (sumerergyMap != null) {
                    Double currentSum = sumerergyMap.get(CURRENT);
                    Double momSum = sumerergyMap.get(MOM);
                    Float momRate = 0f;
//				momSum =30d;
                    if (momSum == 0f) {
                        return;
                    }
                    momRate = (float) Math.round((momSum - currentSum) / momSum * 100);
                    if (momRate > 0 && momRate < 100 && momRate > bankAlarmNotice.getAlarmThr()) {
                        AnalyzeDateSource analyzeDateSource = analyzeDateSourceService.getById(bankAlarmNotice.getDataSourceId());
                        Assert.notNull(analyzeDateSource, "数据源为空!");
                        //通过固定模板id 查询告警模板
                        AlarmNoticeTemplet phoneTemplet = alarmNoticeTempletMapper.selectById(PHONETEMPLETID);
                        //获得模板内容
                        AlarmNoticeTemplet mailTemplet = alarmNoticeTempletMapper.selectById(EMAILTEMPLETID);
                        //只需要邮件的告警模板
                        bankAlarmNotice.setTempletId(mailTemplet.getId());
                        bankAlarmNotice.setTempleteMailContent(mailTemplet.getContent());
                        bankAlarmNotice.setTempletMessageContent(phoneTemplet.getContent());
                        bankAlarmNotice.setDataSourceName(analyzeDateSource.getDatasourceName());
                        bankAlarmNotice.setCurrentStatistic(currentSum);
                        bankAlarmNotice.setMomStatistic(momSum);
                        bankAlarmNotice.setMomRate(momRate);
                        bankAlarmNotice.setContent(bankAlarmNotice.getBankAlarmContent());
                        bankAlarmNotice.setAlarmWay(bankAlarmNotice.getPhoneNumber());
                        bankAlarmNotice.setCurrentPeriodAndMomPeriod(momStatisticModel);
                        BankAlarmNotice bankAlarmNoticeCopy = new BankAlarmNotice();
                        BeanUtils.copyProperties(bankAlarmNotice, bankAlarmNoticeCopy);
                        if (null != bankAlarmNotice.getPhoneNumber()) {
                            sendMessageUtil.sendBankAlarmSms(bankAlarmNotice);
                        }
                        if (null != bankAlarmNotice.getEmailAddress()) {
                            sendEmailUtil.sendBankEmail(bankAlarmNotice);
                        }
                    }

                }
            }
        } catch (ParseException | JsonProcessingException e) {
            LOGGER.error("解析告警变量有异常,终止告警通知,异常明细{}", e);
            return;
        }

    }


    @Override
    public IPage<BankAlarmNotice> getAlarmNoticePage(Page page, BankAlarmNotice alarmNotice) {
        QueryWrapper<BankAlarmNotice> wrapper = new QueryWrapper<BankAlarmNotice>();
        wrapper.eq(null != alarmNotice && alarmNotice.getDataSourceId() != null, "data_source_id", alarmNotice.getDataSourceId());
        wrapper.eq(null != alarmNotice && alarmNotice.getAlarmType() != null, "alarm_type", alarmNotice.getAlarmType());
        wrapper.orderByDesc("alarm_date");
        return bankAlarmNoticeMapper.selectPage(page, wrapper);
    }

    @Override
    public List<BankEnergyAlarmRule> getBankAlarmRuleByDataSourceId(BankEnergyAlarmRule rule) {
        QueryWrapper<BankEnergyAlarmRule> wrapper = new QueryWrapper<BankEnergyAlarmRule>();
        wrapper.eq(rule.getDataSourceId() != null, "data_source_id", rule.getDataSourceId());
        wrapper.eq(rule.getEnergyKind() != null, "energy_kind", rule.getEnergyKind());
        List<BankEnergyAlarmRule> bankEnergyAlarmRuleList = this.list(wrapper);
        for (BankEnergyAlarmRule bankEnergyAlarmRule : bankEnergyAlarmRuleList) {
            EsQuerymodel esQuerymodel = new EsQuerymodel();
            esQuerymodel.setDataSourceId(bankEnergyAlarmRule.getDataSourceId());
            esQuerymodel.setUseKinds(bankEnergyAlarmRule.getEnergyKind());
            esQuerymodel.setMomStatisticKind(bankEnergyAlarmRule.getAlarmType());
            // 周告警
            if (1 == bankEnergyAlarmRule.getAlarmType()) {
                Map<String, Date> map = EsCalendar.getDayOfLastWeek();
                esQuerymodel.setCurrentBeginTime(map.get("mondayDate"));
                esQuerymodel.setCurrentEndTime(map.get("sundayDate"));
            } else {//月告警
                Map<String, Date> map = EsCalendar.getDayOfMonth();
                esQuerymodel.setCurrentBeginTime(map.get("monthBegin"));
                esQuerymodel.setCurrentEndTime(map.get("monthEnd"));
            }
            try {
                MomStatisticModel momStatisticModel = esRealServiceImpl.getMomStatisticData(esQuerymodel);
                Map<String, Map<String, Double>> mapMap = momStatisticModel.getStaticResultMap();
                if (mapMap.containsKey("sumEnergy")) {
                    Map<String, Double> map = mapMap.get("sumEnergy");
                    Double current = map.get("current");
                    Double mom = map.get("mom");
                    int momValue = 0;
                    if (0 != mom) {
                        momValue = (int) ((current - mom) / mom * 100);
                    }
                    String momStr = momValue + "%";
                    bankEnergyAlarmRule.setMomValue(momStr);
                }

            } catch (JsonProcessingException e) {
                e.printStackTrace();
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        return bankEnergyAlarmRuleList;
    }


}
